﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Smark.Core
{
    public class Log
    {
        internal Log()
        {
            Writer = new LogWriteToConsole();
        }
		private LogType mOutputType;
        public LogType OutputType
        {
            get
			{
				return mOutputType;
			}
            internal set
			{
				mOutputType = value;
			}
        }
		private string mName;
        internal string Name
        {
            get
			{
				return mName;
			}
            set
			{
				mName = value;
			}
        }
		private ILogWriter mWriter;
        internal ILogWriter Writer
        {
            get
			{
				return mWriter;
			}
            set
			{
				mWriter = value;
			}
        }
        private IList<Item> mItems = new List<Item>();
        public IList<Item> Items
        {
            get
            {
                return mItems;
            }
        }
        public void Add<T>(Exception e)
        {
            Add<T>(LogType.Error, e.Message, e.StackTrace);
            
        }
        public void Add<T>(LogType type, string message)
        {
            Add<T>(type, message, null);
        }
        public void Add<T>(LogType type, string message, string errorStackTrace)
        {
            
            if ((OutputType & type)>0|| OutputType== LogType.All)
            {
                Item item = new Item();
                item.LogType = type;
                item.Message = message;
                item.ErrorStackTrace = errorStackTrace;
                item.Type = typeof(T);
                System.Threading.ThreadPool.QueueUserWorkItem(
                    OnWriteLog, item);
            }

        }
        private void OnWriteLog(object item)
        {
            Item li = (Item)item;
            Writer.Save(this,li);
        }
        [Serializable]
        public class Item
        {
            public Item()
            {
                Date = DateTime.Now;
            }
			private DateTime mDate;
            public DateTime Date
            {
                get
				{
					return mDate;
				}
                internal set
				{
					mDate = value;
				}
            }
			private string mMessage;
            public string Message
            {
                get
				{
					return mMessage;
				}
                set	
				{
					mMessage = value;
				}

            }
			private Type mType;
            public Type Type
            {
                get
				{
					return mType;
				}
                set
				{
					mType = value;
				}
            }
            public System.Reflection.Assembly Assembly
            {
                get
                {
                    return Type.Assembly;
                }
            }
			private LogType mLogType;
            public LogType LogType
            {
                get
				{
					return mLogType;
				}
                set
				{
					mLogType = value;
				}
            }
			private string mErrorStackTrace;
            public string ErrorStackTrace
            {
                get
				{
					return mErrorStackTrace;
				}
                set
				{
					mErrorStackTrace = value;
				}
            }

        }
        public enum LogType
        {
            Off = 0,
            All =1,
            None = 2,
            Error = 4,
            Warning = 8,
            Debug = 32,
            Debug1 = 64,
            Debug2 = 128,
            Track = 256,
            Track1 = 512,
            Track2 = 1024
          
        }
        public interface ILogWriter
        {
            void Save(Log log,Item item);
        }
        public class LogWriterToFile : ILogWriter
        {

            class LogFile
            {
                public LogFile(string path,string file)
                {
                    Name = file;
                    Writer = new System.IO.StreamWriter(path + file, true, Encoding.UTF8);
                }
				private string mName;
                public string Name
                {
                    get
					{
						return mName;
					}
                    set
					{
						mName = value;
					}
                }
				private System.IO.StreamWriter mWriter;
                public System.IO.StreamWriter Writer
                {
                    get
					{
						return mWriter;
					}
                    set
					{
						mWriter = value;
					}
                }
            }
            static IDictionary<System.Reflection.Assembly, LogFile> mLogFiles = new Dictionary<System.Reflection.Assembly, LogFile>();
            private string mPath = null;
            protected string Path
            {
                get
                {
                    if (mPath == null)
                    {
                        mPath = Functions.AssemblyPath;

                    }
                    return mPath;
                }
            
           
            }
            private LogFile GetLogFile(Item item)
            {
                lock (mLogFiles)
                {
                    string filename = item.Assembly.GetName().Name + item.Date.ToString("yyyyMMdd") + ".log";
                    LogFile result;
                    if (mLogFiles.ContainsKey(item.Assembly))
                    {
                        result = mLogFiles[item.Assembly];
                        if (result.Name != filename)
                        {
                            result.Writer.Close();
                            result = new LogFile(Path, filename);
                            mLogFiles[item.Assembly] = result;
                        }
                    }
                    else
                    {
                        result = new LogFile(Path, filename);
                        mLogFiles.Add(item.Assembly, result);
                    }
                    return result;

                }
            }
            public void Save(Log log,Item item)
            {
                LogFile lf = GetLogFile(item);
                lf.Writer.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", item.Date, item.LogType, item.Type.FullName, item.Message, item.ErrorStackTrace,item.Assembly.GetName().Name);
                lf.Writer.Flush();
            }
        }
        public class LogWriteToConsole : ILogWriter
        {
            #region ILogWriter 成员

            public void Save(Log log, Item item)
            {
                Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", item.Date, item.LogType, item.Type.Name, item.Message, item.ErrorStackTrace, item.Assembly.GetName().Name);
            }

            #endregion
        }
        public static Log Write<T>(LogType type, Exception e)
        {
            return Write<T>(type, e.Message, e.StackTrace);
        }
        public static Log Write<T>(Exception e)
        {
            return Write<T>(LogType.Error, e);
        }
        public static Log Write<T>(LogType type, string message)
        {
            return Write<T>(type, message, null);
        }
        public static Log WriteFormat<T>(LogType type, string formatmsg,params object[] data)
        {
            return Write<T>(type, string.Format(formatmsg,data), null);
        }
        public static Log Write<T>(LogType type, string message, string errorStackTrace)
        {
            Log result = Get<T>();
            result.Add<T>(type, message, errorStackTrace);
            return result;
        }
        static IDictionary<System.Reflection.Assembly, Log> mLogs = new Dictionary<System.Reflection.Assembly, Log>();
        public static Log Get<T>()
        {
            lock (mLogs)
            {
                Log result;
                System.Reflection.Assembly key = typeof(T).Assembly;
                if (!mLogs.ContainsKey(key))
                {
                    result = new Log();
                    mLogs.Add(key, result);
                }
                result = mLogs[key];
                return result;

            }
        }

        public static void SetWriter<TYPE, WRITER>() where WRITER : ILogWriter, new()
        {
            Get<TYPE>().Writer = new WRITER();
        }
        public static void SetWriteLogType<T>(LogType type)
        {
            Get<T>().OutputType = type;
        }
    }

}
